package owg.util;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;

import com.jogamp.opengl.GLContext;

import owg.util.euclidian.MatrixStack;
import owg.util.euclidian.V2D;
import owg.util.opengl.ColorF;
import owg.util.opengl.EGL;

public class Camera2D extends EntityBase {
    public ColorF clearColor = null;
    public V2D pos;
    public V2D speed;
    public V2D size;
    public boolean fixedAspect;
    
    public final Component mainPanel;

    public Camera2D(InstanceList list, V2D pos, V2D size, Component mainPanel, boolean fixedAspect) {
	super(list, Integer.MAX_VALUE);
	this.pos = pos;
	this.size = size;
	this.fixedAspect = fixedAspect;
	this.mainPanel = mainPanel;
	speed = new V2D();
    }

    @Override
    public void beginStep() {
	//Nop
    }

    @Override
    public void step() {
	pos.add(speed);
    }

    @Override
    public void endStep() {
	//Nop
    }
    /**
     * Transforms a normalized viewport position in the range [(0,0) , (1,1)> to a world position relative to this camera.
     * @param x
     * @param y
     * @return
     */
    public V2D normToWorld(float x, float y)
    {
	Rectangle viewport = EGL.getEGL(GLContext.getCurrentGL()).getViewport();
	Dimension winSize = mainPanel.getSize();
	float minX = (float)viewport.x/winSize.width;
	float xRange = (float)viewport.width/winSize.width;
	x = (x-minX)/xRange;//Calc.limit((x-minX)/xRange, 0, 1);
	float minY = (float)viewport.y/winSize.height;
	float yRange = (float)viewport.height/winSize.height;
	y = (y-minY)/yRange;//Calc.limit((y-minY)/yRange, 0, 1);
	return new V2D(x, y).multiply(size.x(), size.y()).add(pos);
    }

    @Override
    public void render() 
    {
	EGL<?> egl = EGL.getEGL(GLContext.getCurrentGL());
	if (fixedAspect) 
	{
	    Rectangle r = getViewport();
	    fillBorder(egl);
	    egl.setViewport(r.x, r.y, r.width, r.height);
	    egl.setScissor(r.x, r.y, r.width, r.height);
	    egl.setScissorEnabled(true);
	}
	if(clearColor != null)
	    egl.clearScreen(clearColor);
	MatrixStack m = egl.projectionMatrix();
	m.identity();
	m.ortho((float)pos.x(), (float)(pos.x()+size.x()), (float)(pos.y()+size.y()), (float)pos.y(), -1, 1);
    }
    private Rectangle getViewport() {
	float goodAspect = (float)(size.x()/size.y());
	    float winAspect = (float)mainPanel.getWidth()/mainPanel.getHeight();
	    int xOff, yOff;
	    int goodWidth, goodHeight;

	    if(goodAspect > winAspect)
	    {
		goodWidth = mainPanel.getWidth();
		goodHeight = (int)(goodWidth/goodAspect);
		xOff = 0;
		yOff = (mainPanel.getHeight()-goodHeight)/2;
	    }
	    else
	    {
		goodHeight = mainPanel.getHeight();
		goodWidth = (int)(goodHeight*goodAspect);
		yOff = 0;
		xOff = (mainPanel.getWidth()-goodWidth)/2;
	    }
	return new Rectangle(xOff, yOff, goodWidth, goodHeight);
    }
    public boolean isOnScreen(V2D v, double hSlack, double vSlack) {
    	return v.x() >= pos.x()-hSlack && v.y() >= pos.y()-vSlack && v.x() <= pos.x()+size.x()+hSlack && v.y() <= pos.y()+size.y()+vSlack;
        }
    public boolean isOnScreen(V2D v, double slack) {
    	return v.x() >= pos.x()-slack && v.y() >= pos.y()-slack && v.x() <= pos.x()+size.x()+slack && v.y() <= pos.y()+size.y()+slack;
        }
    public boolean isOnScreen(V2D v) {
	return v.x() >= pos.x() && v.y() >= pos.y() && v.x() <= pos.x()+size.x() && v.y() <= pos.y()+size.y();
    }

    /**This method may be overridden to paint the border with something else.
     * This is only called if {@link #fixedAspect} is true.
     * Note that the scissor values, viewport, and projection matrix likely need to be explicitly set here.*/
    protected void fillBorder(EGL<?> egl) {
	egl.setScissorEnabled(false);
	egl.clearScreen(ColorF.BLACK);
    }

}
